﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace TagRequester
{
    namespace Http
    {
        public enum HttpRequestType
        {
            String = 0,
            Stream = 1,
        }

        public enum HttpMethod
        {
            GET = 0,
            POST = 1,
        }


        public class Request
        {

            #region Accept  获取或设置 Accept HTTP 标头的值。
            private string _Accept = null;
            /// <summary>
            /// 获取或设置 Accept HTTP 标头的值。
            /// 默认值为 null。 
            /// </summary>
            public string Accept
            {
                get { return _Accept; }
                set { _Accept = value; }
            }
            #endregion

            #region Connection    获取或设置 Connection HTTP 标头的值。
            private string _Connection = null;
            /// <summary>
            /// 获取或设置 Connection HTTP 标头的值。
            /// 默认值为 null。 
            /// </summary>
            public string Connection
            {
                get { return _Connection; }
                set { _Connection = value; }
            }
            #endregion

            #region Cookie    获取或设置与此请求关联的 cookie。
            private string _Cookie = null;
            /// <summary>
            /// 获取或设置与此请求关联的 cookie。
            /// 默认值为 null。
            /// </summary>
            public string Cookie
            {
                get { return _Cookie; }
                set { _Cookie = value; }
            }
            #endregion

            #region Encoding    获取或设置本次请求返回内容的编码格式
            private Encoding _Encoding = Encoding.UTF8;
            /// <summary>
            /// 获取或设置本次请求返回内容的编码格式
            /// 默认值为 Encoding.Default。
            /// </summary>
            public Encoding Encoding
            {
                get { return _Encoding; }
                set { _Encoding = value; }
            }
            #endregion

            #region Headers    指定构成 HTTP 标头的名称/值对的集合。
            private WebHeaderCollection _Headers = new WebHeaderCollection();
            /// <summary>
            /// 指定构成 HTTP 标头的名称/值对的集合。
            /// </summary>
            public WebHeaderCollection Headers
            {
                get { return _Headers; }
                set { _Headers = value; }
            }
            #endregion

            #region KeepAlive    获取或设置一个值，该值指示是否与 Internet 资源建立持久性连接。
            private bool _KeepAlive;
            /// <summary>
            /// 获取或设置一个值，该值指示是否与 Internet 资源建立持久性连接。
            /// 默认值为 true。
            /// </summary>
            public bool KeepAlive
            {
                get { return _KeepAlive; }
                set { _KeepAlive = value; }
            }
            #endregion

            #region Method    获取或设置请求的方法。
            private HttpMethod _Method = HttpMethod.GET;
            /// <summary>
            /// 获取或设置请求的方法。
            /// 默认值是 GET。
            /// </summary>
            public HttpMethod Method
            {
                get { return _Method; }
                set { _Method = value; }
            }
            #endregion

            #region PostParameters    获取或设置当Method为POST的时的请求参数，键值对形式。
            private Dictionary<string, string> _PostParameters = new Dictionary<string, string>();
            /// <summary>
            /// 获取或设置当Method为POST的时的请求参数，键值对形式。
            /// 此值不可设置为null
            /// </summary>
            public Dictionary<string, string> PostParameters
            {
                get { return _PostParameters; }
                set
                {
                    if (value == null)
                    {
                        return;
                    }
                    _PostParameters = value;
                }
            }
            #endregion

            #region PostData    获取或设置当Method为POST的时的请求参数，字符串形式。
            private string _PostData = string.Empty;
            /// <summary>
            /// 获取或设置当Method为POST的时的请求参数，字符串形式。
            /// 当PostParameters的Count>0的时候，此值在请求时不会生效，并且获取该值将返回PostParameters的字符串形式
            /// 默认值为 null。
            /// </summary>
            public string PostData
            {
                get
                {
                    if (this.PostParameters.Count > 0)
                    {
                        _PostData = string.Empty;
                        foreach (var item in PostParameters)
                        {
                            if (_PostData != string.Empty)
                                _PostData += "&";
                            _PostData += item.Key + "=" + item.Value;
                        }
                    }
                    return _PostData;
                }
                set { _PostData = value; }
            }
            #endregion

            #region ProtocolVersion    获取或设置用于请求的 HTTP 版本。
            private Version _ProtocolVersion = HttpVersion.Version11;
            /// <summary>
            /// 获取或设置用于请求的 HTTP 版本。
            /// 默认值为 HttpVersion.Version11。 
            /// </summary>
            public Version ProtocolVersion
            {
                get { return _ProtocolVersion; }
                set { _ProtocolVersion = value; }
            }
            #endregion

            #region Referer    获取或设置 RefererHTTP 标头的值。
            private string _Referer = string.Empty;
            /// <summary>
            /// 获取或设置 RefererHTTP 标头的值。
            /// 默认值为 null。 
            /// </summary>
            public string Referer
            {
                get { return _Referer; }
                set { _Referer = value; }
            }
            #endregion

            #region RequestType    获取或设置本次请求的类型。
            private HttpRequestType _RequestType = HttpRequestType.String;
            /// <summary>
            /// 获取或设置本次请求的类型。
            /// 默认值为 String
            /// </summary>
            public HttpRequestType RequestType
            {
                get { return _RequestType; }
                set { _RequestType = value; }
            }
            #endregion

            #region Timeout    获取或设置 GetResponse 和 GetRequestStream 方法的超时值（以毫秒为单位）。
            private int _Timeout = 100000;
            /// <summary>
            /// 获取或设置 GetResponse 和 GetRequestStream 方法的超时值（以毫秒为单位）。
            /// 默认值是 100,000 毫秒（100 秒）。
            /// </summary>
            public int Timeout
            {
                get { return _Timeout; }
                set { _Timeout = value; }
            }
            #endregion

            #region Url    获取或设置本次请求的Url，必须设置该属性的值，否则GetResponse()会引发异常
            private string _Url = string.Empty;
            /// <summary>
            /// 获取或设置本次请求的Url，必须设置该属性的值，否则GetResponse()会引发异常
            /// 默认值为 null
            /// </summary>
            public string Url
            {
                get { return _Url; }
                set { _Url = value; }
            }
            #endregion

            #region UserAgent    获取或设置 User-agentHTTP 标头的值。
            private string _UserAgent = null;
            /// <summary>
            /// 获取或设置 User-agentHTTP 标头的值。
            /// 默认值为 null。 
            /// </summary>
            public string UserAgent
            {
                get { return _UserAgent; }
                set { _UserAgent = value; }
            }
            #endregion

            #region ProxyHost    获取或设置本次请求的代理主机地址
            private string _proxyHost = string.Empty;
            /// <summary>
            /// 获取或设置本次请求的代理主机地址
            /// </summary>
            public string ProxyHost
            {
                get { return _proxyHost; }
                set { _proxyHost = value; }
            }
            #endregion

            #region ProxyPort    获取或设置本次请求的代理主机端口
            private int _proxyPort = 0;
            /// <summary>
            /// 获取或设置本次请求的代理主机端口
            /// </summary>
            public int ProxyPort
            {
                get { return _proxyPort; }
                set { _proxyPort = value; }
            }

            #endregion

            public Request()
            {

            }
            public Request(string url)
            {
                this.Url = url;
            }

            public Response GetResponse()
            {
                Response response = new Response();
                try
                {

                    #region 创建HttpWebRequest请求对象
                    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(this.Url);
                    #endregion

                    #region 设置基本参数，此处默认值都与HttpWebRequest保持一致
                    req.Accept = this.Accept;
                    req.KeepAlive = this.KeepAlive;
                    req.ProtocolVersion = this.ProtocolVersion;
                    req.Referer = this.Referer;
                    req.Timeout = this.Timeout;
                    req.UserAgent = this.UserAgent;
                    #endregion

                    #region 设置代理
                    if (!string.IsNullOrEmpty(this.ProxyHost) || this.ProxyPort != 0)
                    {
                        req.Proxy = new WebProxy(this.ProxyHost, this.ProxyPort);
                    }
                    #endregion

                    #region 设置Headers
                    foreach (var item in this.Headers.AllKeys)
                    {
                        req.Headers.Add(item, this.Headers[item]);
                    }
                    #endregion

                    #region 设置Cookie，暂未添加CookieContainer
                    req.Headers["cookie"] = this.Cookie;
                    #endregion

                    #region Method，如果是Post要写入数据
                    if (this.Method == HttpMethod.POST)
                    {
                        req.Method = "POST";
                        System.Text.UTF8Encoding encoding = new UTF8Encoding();
                        byte[] buffer = encoding.GetBytes(this.PostData);//此处this.PostData属性的get方法里面已经自动处理好该使用什么作为post参数
                        req.ContentType = "application/x-www-form-urlencoded";
                        req.ContentLength = buffer.Length;
                        using (Stream s = req.GetRequestStream())
                        {
                            s.Write(buffer, 0, buffer.Length);
                        }
                    }
                    #endregion

                    #region 开始请求

                    #region 得到HttpWebResoponse对象
                    HttpWebResponse res;
                    try
                    {
                        res = (HttpWebResponse)req.GetResponse();
                    }
                    catch (WebException ex)
                    {
                        res = (HttpWebResponse)ex.Response;
                    }
                    #endregion

                    #region 设置响应状态
                    response.SetStatusCode(res.StatusCode);
                    response.SetStatusDescription(res.StatusDescription);
                    #endregion

                    #region 设置响应头
                    response.SetHeaders(res.Headers);
                    #endregion

                    #region 设置响应内容
                    switch (this.RequestType)
                    {
                        case HttpRequestType.String:
                            using (StreamReader sr = new StreamReader(res.GetResponseStream(), this.Encoding))
                            {
                                response.SetContent(sr.ReadToEnd());
                            }
                            break;
                        case HttpRequestType.Stream:
                            response.SetStream(res.GetResponseStream());
                            break;
                        default:
                            break;
                    }
                    #endregion

                    #endregion
                }
                catch (Exception ex)
                {
                    response.SetSuccess(false);
                    response.SetContent(ex.Message);
                }
                return response;
            }

            #region 设置代理
            /// <summary>
            /// 设置代理
            /// </summary>
            /// <param name="address">格式 127.0.0.1:8080 </param>
            public void SetProxy(string address)
            {
                string[] result = address.Split(':');
                if (result.Length > 1)
                {
                    this.ProxyHost = result[0].Trim();
                    this.ProxyPort = int.Parse(result[1].Trim());
                }
            }
            #endregion
        }

        /// <summary>
        /// 服务器返回数据，全都是只读！
        /// </summary>
        public class Response
        {
            private string _Content = null;
            /// <summary>
            /// 获取本次请求返回的内容
            /// </summary>
            public string Content
            {
                get { return _Content; }
            }

            private WebHeaderCollection _Headers = new WebHeaderCollection();
            /// <summary>
            /// 获取来自服务器的与此响应关联的标头。
            /// </summary>
            public WebHeaderCollection Headers
            {
                get { return _Headers; }
            }

            private Stream _Stream = null;
            /// <summary>
            /// 获取本次请求返回的Stream
            /// </summary>
            public Stream Stream
            {
                get { return _Stream; }
            }

            private HttpStatusCode _StatusCode;
            /// <summary>
            /// 获取响应的状态。
            /// </summary>
            public HttpStatusCode StatusCode
            {
                get { return _StatusCode; }
            }

            private string _StatusDescription;
            /// <summary>
            /// 获取与响应一起返回的状态说明。
            /// </summary>
            public string StatusDescription
            {
                get { return _StatusDescription; }
            }

            private bool _Success = true;
            /// <summary>
            /// 指示本次请求是否成功
            /// 失败包括（请求参数配置错误，网络错误等等）
            /// </summary>
            public bool Success
            {
                get { return _Success; }
            }

            public Response()
            {

            }


            public void SetHeaders(WebHeaderCollection headers)
            {
                this._Headers = headers;
            }

            public void SetContent(string content)
            {
                this._Content = content;
            }

            public void SetStream(Stream stream)
            {
                this._Stream = stream;
            }

            public void SetStatusCode(HttpStatusCode code)
            {
                this._StatusCode = code;
            }

            public void SetStatusDescription(string description)
            {
                this._StatusDescription = description;
            }

            public void SetSuccess(bool success)
            {
                this._Success = success;
            }

        }


    }

}
